package com.rj.core.algorithm;

import com.rj.util.ByteUtils;
import org.bouncycastle.crypto.engines.SM2Engine;
import org.bouncycastle.jcajce.provider.digest.Skein;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Hex;

import javax.crypto.Cipher;
import java.security.*;


/**
 * 类型安全的加解密工具类（数据结构体传参）
 */
public class CryptoUtils {
    static {
        Security.addProvider(new BouncyCastleProvider());
    }

    /**
     * 加密函数
     *
     * @param algorithm 加密算法
     * @param data      数据
     * @param key       密钥
     * @param iv        初始向量
     */
    public static byte[] encrypt(SymmetricAlgorithm algorithm, byte[] data, byte[] key, byte[] iv) {
        return algorithm.crypt(data, Cipher.ENCRYPT_MODE, key, iv);
    }

    /**
     * 加密函数
     *
     * @param algorithm 加密算法
     * @param data      数据
     * @param key       密钥
     */
    public static byte[] encrypt(SymmetricAlgorithm algorithm, byte[] data, byte[] key) {
        return encrypt(algorithm, data, key, null);
    }

    /**
     * 解密函数
     *
     * @param algorithm 加密算法
     * @param data      数据
     * @param key       密钥
     * @param iv        初始向量
     */
    public static byte[] decrypt(SymmetricAlgorithm algorithm, byte[] data, byte[] key, byte[] iv) {
        return algorithm.crypt(data, Cipher.DECRYPT_MODE, key, iv);
    }

    /**
     * 解密函数
     *
     * @param algorithm 加密算法
     * @param data      数据
     * @param key       密钥
     */
    public static byte[] decrypt(SymmetricAlgorithm algorithm, byte[] data, byte[] key) {
        return decrypt(algorithm, data, key, null);
    }


    /**
     * 解密函数
     *
     * @param algorithm       加密算法
     * @param dataBytes       数据
     * @param privateKeyBytes 密钥
     */
    public static byte[] decrypt(RsaAgorithm algorithm, byte[] dataBytes, byte[] privateKeyBytes) {
        return algorithm.crypt(Cipher.DECRYPT_MODE, dataBytes, privateKeyBytes);
    }

    /**
     * Rsa加密函数
     *
     * @param algorithm      加密算法
     * @param dataBytes      数据
     * @param publicKeyBytes 密钥
     */
    public static byte[] encrypt(RsaAgorithm algorithm, byte[] dataBytes, byte[] publicKeyBytes) {
        return algorithm.crypt(Cipher.ENCRYPT_MODE, dataBytes, publicKeyBytes);
    }

    /**
     * 计算哈希值
     *
     * @param hashAlgorithm 哈希算法
     * @param data          数据
     */
    public static byte[] hash(HashAlgorithm hashAlgorithm, byte[] data) throws Exception {
        MessageDigest digest = MessageDigest.getInstance(hashAlgorithm.name());
        return digest.digest(data);
    }

    /**
     * 哈希计算
     *
     * @param hmacAlgorithm
     * @param data
     * @param key
     * @return
     */
    public static byte[] hash(HmacAlgorithm hmacAlgorithm, byte[] data, byte[] key) throws Exception {
        return hmacAlgorithm.computeHmac(data, key);
    }

    /**
     * 签名
     *
     * @param algorithm
     * @param data
     * @param privateKeyBytes
     * @param userIdBytes
     * @return
     */

    public static byte[] sign(SM2Algorithm algorithm, byte[] data, byte[] privateKeyBytes, byte[] userIdBytes) {
        return algorithm.sign(data, algorithm.getPrivateKey(privateKeyBytes), userIdBytes);
    }

    /**
     * 验签
     *
     * @param algorithm
     * @param data
     * @param signatureData
     * @param publicKey
     * @param userId
     * @return
     */

    public static boolean verify(SM2Algorithm algorithm, byte[] data, byte[] signatureData, byte[] publicKey,
                                 byte[] userId) {
        return algorithm.verify(data, signatureData, algorithm.getPublicKey(publicKey), userId);
    }


    /**
     * SM2加密
     *
     * @param algorithm
     * @param data
     * @param data
     * @param mode
     * @return
     * @throws Exception
     */
    public static byte[] encrypt(SM2Algorithm algorithm, byte[] data, byte[] publicKey, SM2Engine.Mode mode) {
        return algorithm.crypt(data, algorithm.getPublicKey(publicKey), mode);
    }

    /**
     * SM2解密
     *
     * @param algorithm
     * @param cipherData
     * @param privateKey
     * @param mode
     * @return
     * @throws Exception
     */
    public static byte[] decrypt(SM2Algorithm algorithm, byte[] cipherData, byte[] privateKey, SM2Engine.Mode mode) {
        return algorithm.crypt(cipherData, algorithm.getPrivateKey(privateKey), mode);
    }

}

